use std::{
	fmt::{Debug, Display, Formatter},
	net::SocketAddr,
};

use event::ChannelEvent;
use tokio::sync::mpsc::{self, error::TryRecvError};
use tools::{enum_generator, ResultEx};
use tracing::info;

pub mod event;

#[derive(Clone, PartialEq, Eq)]
pub enum EndReason {
	InvalidTarget,
	ChannelUnusable,
	NoCalledNum,
	InvalidCalled(String),
	TalkEnd,
	NotGayWay,
	UserNotRegister,
	Transfer,
	CalledHangup(String),
	ServerInternalError,
	NoMessageExchanged,
	///代表由业务逻辑主动挂断,具体原因由业务逻辑决定.
	/// 如果业务逻辑接收到此挂断原因,应该忽略.
	InitiativeHangup,
	///对应会话层异常...
	SissionError,
	UnknownValue,
	///拨测
	DialTest,
	NotEnoughMoney,
	NoAllowTimeCaller,
	///号码被暂停
	PhonePause,
	TalkNocallerd,
	NoInWhiteListCaller,
	InBlackListCaller,
	NoAllowRegionCaller,
	/**正常IVR通话接通但无被叫(漏电)*/
	IvrTalkNocallerd,
	IvrTalkCallerPending,
	///没有对应的节点
	NotSetNode,
	AllBusy,
	LeaveMessageOver,
	NotSetNumber,
	CallerPending,
	CallSelf,
	CalledIsCalling,
	Overtime,
}

impl From<EndReason> for i32 {
	fn from(value: EndReason) -> Self {
		match value {
			EndReason::ChannelUnusable => 1,
			EndReason::NoCalledNum => 100,
			EndReason::InvalidCalled(_) => 101,
			EndReason::TalkEnd => 38,
			EndReason::NotGayWay => 300,
			EndReason::UserNotRegister => 302,
			EndReason::Transfer => 301,
			EndReason::CalledHangup(_) => 400,
			EndReason::ServerInternalError => 500,
			EndReason::NoMessageExchanged => 601,
			EndReason::InitiativeHangup => 700,
			EndReason::SissionError => 701,
			EndReason::UnknownValue => 9999,
			EndReason::InvalidTarget => 100,
			EndReason::DialTest => 99,
			EndReason::NotEnoughMoney => 101,
			EndReason::NotSetNode => 102,
			EndReason::PhonePause => 103,
			EndReason::AllBusy => 110,
			EndReason::NoInWhiteListCaller => 120,
			EndReason::InBlackListCaller => 121,
			EndReason::NoAllowTimeCaller => 122,
			EndReason::NoAllowRegionCaller => 123,
			// EndReason::CallSelf => 105,
			// EndReason::Unknow => 0,
			// EndReason::NotSetNumber => 125,
			// EndReason::ALLInCalled => 104,
			// EndReason::NotFoundConfig => 201,
			// EndReason::UseUnavailable => 200,
			// EndReason::UserUnregistered => 202,
			EndReason::TalkNocallerd => 0,
			EndReason::IvrTalkNocallerd => 2,
			EndReason::IvrTalkCallerPending => 18,
			EndReason::LeaveMessageOver => 11,
			EndReason::NotSetNumber => 125,
			EndReason::CallerPending => 37,
			EndReason::CallSelf => 105,
			EndReason::CalledIsCalling => 41,
			EndReason::Overtime => 202,
		}
	}
}

impl From<i32> for EndReason {
	fn from(code: i32) -> Self {
		match code {
			1 => Self::ChannelUnusable,
			100 => Self::NoCalledNum,
			101 => Self::InvalidCalled(String::default()),
			200 => Self::TalkEnd,
			300 => Self::NotGayWay,
			301 => Self::Transfer,
			302 => Self::UserNotRegister,
			400 => Self::CalledHangup(String::default()),
			500 => Self::ServerInternalError,
			601 => Self::NoMessageExchanged,
			700 => Self::InitiativeHangup,
			_ => Self::UnknownValue,
		}
	}
}

#[inline]
fn fmt(slf: &EndReason, f: &mut Formatter<'_>) -> std::fmt::Result {
	match slf {
		EndReason::ChannelUnusable => write!(f, "通道不可用"),
		EndReason::NoCalledNum => write!(f, "不存在被叫号码"),
		EndReason::InvalidCalled(m) => write!(f, "无效的被叫号码,{}", m),
		EndReason::TalkEnd => write!(f, "正常通话结束"),
		EndReason::NotGayWay => write!(f, "没有可用的网关"),
		EndReason::CalledHangup(m) => write!(f, "被叫主动挂断..msg:{m}"),
		EndReason::ServerInternalError => write!(f, "服务器内部错误"),
		EndReason::NoMessageExchanged => write!(f, "通话过程中长时间没有交换信息"),
		EndReason::UnknownValue => write!(f, "未知的挂断原因"),
		EndReason::Transfer => write!(f, "呼叫转移"),
		EndReason::InitiativeHangup => write!(f, "业务主动挂断"),
		EndReason::SissionError => write!(f, "网络对接握手失败"),
		EndReason::UserNotRegister => write!(f, "用户未注册"),
		EndReason::InvalidTarget => write!(f, "无此业务号码"),
		EndReason::DialTest => write!(f, "拨测呼入"),
		EndReason::NotEnoughMoney => write!(f, "余额不足"),
		EndReason::PhonePause => write!(f, "号码被暂停"),
		EndReason::TalkNocallerd => write!(f, "接通但无被叫"),
		EndReason::NoInWhiteListCaller => write!(f, "白名单拒接"),
		EndReason::InBlackListCaller => write!(f, "黑名单拒接"),
		EndReason::NoAllowTimeCaller => write!(f, "时段拒接"),
		EndReason::NoAllowRegionCaller => write!(f, "区域限制拒接"),
		EndReason::IvrTalkNocallerd => write!(f, "IVR通话接通但无被叫"),
		EndReason::IvrTalkCallerPending => write!(f, "IVR通话接通主叫挂机"),
		EndReason::NotSetNode => write!(f, "没有对应的节点"),
		EndReason::AllBusy => write!(f, "号码全忙"),
		EndReason::LeaveMessageOver => write!(f, "留言结束"),
		EndReason::NotSetNumber => write!(f, "未设置转接电话"),
		EndReason::CallerPending => write!(f, "主叫挂机"),
		EndReason::CallSelf => write!(f, "主被叫相同"),
		EndReason::CalledIsCalling => write!(f, "号码已经在呼叫中"),
		EndReason::Overtime => write!(f, "超时"),
		// EndReason::CallSelf => write!(f, ""),
		// EndReason::NotSetNumber => write!(f, ""),
		// EndReason::ALLInCalled => write!(f, ""),
		// EndReason::NotFoundConfig => write!(f, ""),
		// EndReason::UseUnavailable => write!(f, ""),
		// EndReason::UserUnregistered => write!(f, ""),
	}
}

impl Debug for EndReason {
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		fmt(self, f)
	}
}

impl Display for EndReason {
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		fmt(self, f)
	}
}

///对外呼叫的通道相关信息,此结构用于呼叫时创建
#[derive(Debug)]
pub struct OriginateChannel {
	pub id: u32,
	pub to_switch: mpsc::Sender<CommandMsg>,
	pub from_switch: mpsc::Receiver<ChannelEvent>,
}

impl From<OriginateChannel> for Channel {
	fn from(slf: OriginateChannel) -> Self {
		Self {
			id: slf.id,
			state: ChannelState::Down,
			direction: ChannelCallDirection::OutBound,
			caller_num: String::default(),
			dest_num: String::default(),
			to_switch: slf.to_switch,
			from_switch: slf.from_switch,
		}
	}
}

///通道的结构,对外统一使用此代表一个通道.
///通常一个通话会使用两个通道.一个呼入,一个呼出. 也有可能是两个呼出
/// 此结构的对象只能由此结构内产生.产生时将会同时生成交互时的对象
/// 只能进行内部修改..当接收到消息时,将会同步内部状态
///
/// from_switch 将接收来自于交换方面的事件消息
/// to_switch 将需要执行的命令向交换方面发送
pub struct Channel {
	pub id: u32,
	pub state: ChannelState,
	pub direction: ChannelCallDirection,
	///此通道的主叫号码
	pub caller_num: String,
	///此通道的被叫号码.
	pub dest_num: String,
	pub to_switch: mpsc::Sender<CommandMsg>,
	pub from_switch: mpsc::Receiver<ChannelEvent>,
}

impl Display for Channel {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.fmt_a(f)
	}
}

impl std::fmt::Debug for Channel {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.fmt_a(f)
	}
}

impl Channel {
	#[inline]
	fn fmt_a(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		write!(
			f,
			"Channel {{id: {}, state: {}, direction: {}, caller_num: {}, dest_num: {}}}",
			self.id, self.state, self.direction, self.caller_num, self.dest_num,
		)
	}

	pub fn send(&self, command: CommandMsg) -> ResultEx<()> {
		Ok(self.to_switch.try_send(command)?)
	}

	pub async fn recv(&mut self) -> ResultEx<ChannelEvent> {
		match self.from_switch.recv().await {
			Some(ChannelEvent::ChannelCallState(id, state)) => {
				info!("状态修改,原{},现{}", self.state, state);
				self.state = state;
				Ok(ChannelEvent::ChannelCallState(id, state))
			}
			Some(v) => Ok(v),
			None => Err(tools::error::Error::UniversalError("发送端已经退出.")),
		}
	}

	#[inline]
	pub fn try_recv(&mut self) -> Result<ChannelEvent, TryRecvError> {
		match self.from_switch.try_recv() {
			Ok(ChannelEvent::ChannelCallState(id, state)) => {
				info!("状态修改,原{},现{}", self.state, state);
				self.state = state;
				Ok(ChannelEvent::ChannelCallState(id, state))
			}
			Ok(v) => Ok(v),
			Err(e) => Err(e),
		}
	}

	pub fn id(&self) -> u32 {
		self.id
	}

	pub fn state(&self) -> ChannelState {
		self.state
	}

	pub fn direction(&self) -> ChannelCallDirection {
		self.direction
	}
	pub fn caller_num(&self) -> &str {
		&self.caller_num
	}

	pub fn dest_num(&self) -> &str {
		&self.dest_num
	}

	pub fn from_switch_mut(&mut self) -> &mut mpsc::Receiver<ChannelEvent> {
		&mut self.from_switch
	}
}

enum_generator! {
	;
	ChannelState { //通道状态
		Down("空",0),
		CallIn("初始呼入",100),
		CallOut("初始呼出",101),
		Ringing("振铃中",180),
		Early("早期媒体",183),
		Answered("已接通",200),
		Hangup("已挂断",1),
	}
}

enum_generator! {
	;
	ChannelCallDirection { //呼叫方向
		InBound("呼入",0),
		OutBound("呼出",1)
	}
}

#[derive(Debug)]
pub enum CommandMsg {
	Originate(OriginateMsg),
	Ringing,
	PreAnswer,
	PlayBell(String),
	PlayBellList(Vec<String>),
	StopPlayBell,
	AnswerCall(u32),
	///代表直接杀死通道,不算他处于什么状态
	KillChannel(u32),
	///将当前dialog桥接到另一个dialog.
	BridgeChannel(u32),
	///代表发送挂断消息.原因可以转换并发送出去
	HangupChannel(u32, EndReason),
	SetVar,
	StartRecordSound(String),
	StopRecordSound,
	SendDtmf(u32, String),
}

enum_generator! {
	;
	CallLeg { //表明呼叫的某一方
		ALeg("A腿",1),
		BLeg("B腿",2),
	}
}

#[derive(Debug)]
pub struct OriginateMsg {
	pub master_ch_id: u32,
	pub caller_num: String,
	pub called_num: String,
	pub caller_name: String,
	pub way: OriginateWay,
}

impl OriginateMsg {
	pub fn new(
		master_ch_id: u32,
		caller_num: String,
		called_num: String,
		caller_name: String,
		way: OriginateWay,
	) -> Self {
		Self {
			master_ch_id,
			caller_num,
			called_num,
			caller_name,
			way,
		}
	}
}

///呼叫的方式.
#[derive(Debug)]
pub enum OriginateWay {
	///运营商的网关
	IspGateway,
	///通过外部网关进行呼叫.此呼叫需要指定被叫的IP地址.
	ExternalGateway(SocketAddr),
	//通过用户进行呼叫
	RegisterUser,
	UnKnown,
}

impl OriginateWay {
	///使用配置项的默认外呼网关进行外呼
	pub fn with_external(peer_addr: SocketAddr) -> Self {
		Self::ExternalGateway(peer_addr)
	}
}
